/**
* Author: 	XU Songgang
* Email:	sxu@ust.hk
*
*/


#ifndef __ASSERT_HPP_
#define __ASSERT_HPP_

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fstream>

struct DEG_MESSAGE
{
	string filename ;
        string funname ; 
        int    linenum ;
	int    score;
};

#define ASSERT(COND)\
	assert_ex(COND, __FILE__, __FUNCTION__, __LINE__);

#define TEST_SUITE_BEGIN(SUITE_NAME)\
	vector<string> error_msg;\
	int	score = 0;\
	pid_t 	pc, pr;\
	int status = 0;	\
	int counter = 0; 	\
	string suite_name = SUITE_NAME;\

#define TEST(FUNC,NAME)\
		status  = 0;\
		counter = 0;\
                pc = fork();\
                if (0 == pc)\
                {\
			try{\
                        	FUNC ;\
			}\
			catch(...)\
			{\
				return 1;\
			}\
			return 0;\
                }\
                else\
                {\
                        do\
                        {\
                                pr = waitpid(pc, &status, WNOHANG);\
                                if (pr == 0) usleep(1000);\
                                ++counter;\
                        } while (0 == pr && counter < 5000);\
                        if (0 == pr)\
                        {\
                                cout<<"[   FAIL  ] "<<"Exceed Time Limit   "<<NAME<<endl;\
				kill(pc, SIGTERM);\
                        }\
                        else\
                        if (WIFSIGNALED(status))\
                        {\
                                cout<<"[   FAIL  ] "<<"Segment Fault       "<<NAME<<endl;\
                        }\
                        else\
			if (0 != status)\
			{\
				cout<<"[   FAIL  ] "<<"Wrong Answers       "<<NAME<<endl;\
			}\
			else\
			{\
				cout<<"[ SUCCESS ] "<<"                    "<<NAME<<""<<endl;\
			}\
		}\

#define TEST_SUITE_END()\
{\
}
template <typename type>
void assert_ex (type condition, const char * filename = __FILE__, 
			     const char * funname  = __FUNCTION__,
			     const int    linenum = __LINE__ )
{
	DEG_MESSAGE 	msg ;
	msg.filename 	= filename;
	msg.funname 	= funname;
	msg.linenum 	= linenum;
	try
	{
		if (condition) ;
		else throw (msg);
	}
	catch(DEG_MESSAGE msg)
	{
		std::cerr<<"[ASSERT FAIL] File: "<<msg.filename<<", Line ("<<msg.linenum<<"), Function: " <<msg.funname<<'.'<<std::endl;
		throw(msg);
	}
	catch(...)
	{
		std::cerr<<"[ASSERT FAIL] Unexpected exception. "<<std::endl;
		throw(msg);
	}
}
#endif
